package com.appistry.storage.domain.impl;

import java.io.InputStream;
import java.net.InetAddress;
import java.util.List;

import com.appistry.api.rest.domain.RestResponse;
import com.appistry.storage.File;
import com.appistry.storage.Storage;
import com.appistry.storage.Worker;
import com.appistry.storage.domain.AbstractRestDomainObject;
import com.appistry.storage.exception.StorageManagerException;
import com.appistry.storage.rest.RestStorageManager;
import com.appistry.storage.util.JsonTransformUtil;

public class StorageImpl extends AbstractRestDomainObject implements Storage {
	private RestStorageManager manager;

	public StorageImpl(RestStorageManager manager) {
		this.manager = manager;
	}

	public void addWorker(String ip) throws StorageManagerException {
		try {
			RestResponse response = manager.addWorkerResource(InetAddress.getByName(ip));
			checkForErrors(response);

		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public void deleteFile(String fileName) throws StorageManagerException {
		try {
			RestResponse response = manager.deleteFile(fileName);
			checkForErrors(response);

		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public InputStream getFile(String path) throws StorageManagerException {
		try {
			RestResponse response = manager.getFile(path);
			checkForErrors(response);

			return response.getBodyAsStream();
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public InputStream getFile(String path, int minReadCopies) throws StorageManagerException {
		try {
			RestResponse response = manager.getFile(path, minReadCopies);
			checkForErrors(response);

			return response.getBodyAsStream();
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public InputStream getFile(String path, String version) throws StorageManagerException {
		try {
			RestResponse response = manager.getFile(path, version);
			checkForErrors(response);

			return response.getBodyAsStream();
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public InputStream getFile(String path, int minReadCopies, long offset, long length) throws StorageManagerException {
		try {
			RestResponse response = manager.getFile(path, minReadCopies, offset, length);
			checkForErrors(response);

			return response.getBodyAsStream();
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public InputStream getFile(String path, long offset, long length) throws StorageManagerException {
		try {
			RestResponse response = manager.getFile(path, offset, length);
			checkForErrors(response);

			return response.getBodyAsStream();
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public InputStream getFile(String path, String version, int minReadCopies) throws StorageManagerException {
		try {
			RestResponse response = manager.getFile(path, version, minReadCopies);
			checkForErrors(response);

			return response.getBodyAsStream();
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public InputStream getFile(String path, String version, int minReadCopies, long offset, long length) throws StorageManagerException {
		try {
			RestResponse response = manager.getFile(path, version, minReadCopies, offset, length);
			checkForErrors(response);

			return response.getBodyAsStream();
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public List<File> getFiles(String path) throws StorageManagerException {
		try {
			RestResponse response = manager.listFiles(path);
			checkForErrors(response);

			List<File> files = JsonTransformUtil.toFiles(manager, response.getBodyAsString());
			
			return files;
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public List<File> getFilesWithMetaData(String path) throws StorageManagerException {
		try {
			RestResponse response = manager.listFilesWithMetaData(path);
			checkForErrors(response);

			List<File> files = JsonTransformUtil.toFilesWithMetaData(manager, response.getBodyAsString());

			return files;
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public List<String> getTerritories() throws StorageManagerException {
		try {
			RestResponse response = manager.getTerritories();
			checkForErrors(response);

			List<String> territories = JsonTransformUtil.toTerritories(response.getBodyAsString());
			
			return territories;
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public Worker getWorker(String ip) throws StorageManagerException {
		// TODO research if this is usable
		throw new UnsupportedOperationException("Not yet implemented!");
	}

	public List<Worker> getWorkers() throws StorageManagerException {
		return getWorkers(false);
	}

	public List<Worker> getWorkers(boolean showDeleted) throws StorageManagerException {
		try {
			RestResponse response = manager.listWorkers(showDeleted);
			checkForErrors(response);

			List<Worker> workers = JsonTransformUtil.toWorkers(manager, response.getBodyAsString());
			
			return workers;
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public List<Worker> getWorkers(String territory) throws StorageManagerException {
		try {
			RestResponse response = manager.getTerritoryWorkers(territory);
			checkForErrors(response);

			List<Worker> workers = JsonTransformUtil.toWorkersByTerritories(manager, response.getBodyAsString());
			
			return workers;
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public void moveFile(String fileNameSource, String fileNameDest) throws StorageManagerException {
		try {
			// InputStream content = new ByteArrayInputStream(fileNameDest.toString().getBytes());
			RestResponse response = manager.moveFile(fileNameSource, fileNameDest);
			checkForErrors(response);
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public void putFile(String fileName, long length, InputStream content) throws StorageManagerException {
		try {
			RestResponse response = manager.putFile(fileName, length, content);
			checkForErrors(response);
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}

	}

	public void putFile(String fileName, InputStream content) throws StorageManagerException {
		try {
			RestResponse response = manager.putFile(fileName, content);
			checkForErrors(response);
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}

	}

	public void putFile(String fileName, InputStream content, int copies, int minCopies, int minReadCopies) throws StorageManagerException {
		try {
			RestResponse response = manager.putFile(fileName, content, copies, minCopies, minReadCopies);
			checkForErrors(response);
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public void removeWorker(String ip) throws StorageManagerException {
		try {
			RestResponse response = manager.removeWorkerResource(InetAddress.getByName(ip));
			checkForErrors(response);
		} catch (StorageManagerException e) {
			throw e;
		} catch (Exception e) {
			throw new StorageManagerException(e);
		}
	}

	public File getFileRef(String path) throws StorageManagerException {
		return new FileImpl(manager, path);		
	}

}
